//
//  CELogClient.m
//  CELog_Example
//
//  Created by maoerduo on 2021/2/25.
//  Copyright © 2021 maoerduo. All rights reserved.
//

#import "CELogClient.h"
#import "CEEventLog.h"
#import "CEDurationEventLog.h"
#import "CEPageLog.h"
#import "CEDurationPageLog.h"
#import "AliyunLog/AliyunLogObjc.h"

@interface CELogClient() {
    
    dispatch_queue_t _workQueue;
    
}

@property (nonatomic, strong) id<CECommonLog> currentCommonLog;

@property (nonatomic, strong) NSMutableDictionary * durationLogs;

@property (nonatomic, strong) NSMutableDictionary * failedLogs;

@property (nonatomic, strong) LogClient * aliyunLogClient;

@end

@implementation CELogClient

+ (instancetype)shared {
    
    static CELogClient * client;
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        client = [[self alloc] init];
    });
    
    return client;

}

+ (instancetype)clientWithConfig:(CELogClientConfig *)config {
    
    CELogClient * client = [[CELogClient alloc] init];
    
    [client setupWithConfig:config];
    
    return client;
    
}

- (instancetype)init {
    self = [super init];
    if (self) {
        
        self->_workQueue = dispatch_queue_create("com.maoerduo.log", NULL);
        
        self.durationLogs = [NSMutableDictionary dictionary];
        
    }
    return self;
}

#pragma mark - 初始化

- (void)setupWithConfig:(CELogClientConfig *)config {
    
    self->_logConfig = config;
    
    self.aliyunLogClient = [[LogClient alloc] initWithApp:self->_logConfig.endPoint
                                              accessKeyID:self->_logConfig.accessKeyID
                                          accessKeySecret:self->_logConfig.accessKeySecret
                                              projectName:self->_logConfig.projectName
                                            serializeType:AliSLSJSONSerializer];
    
    
}

- (void)setCommonLog:(id<CECommonLog>)commonLog {
    self.currentCommonLog = commonLog;
}

#pragma mark - 日志方法

- (void)logEvent:(NSString *)eventName {
    
    [self logEvent:eventName log:nil];
    
}

- (void)logEvent:(NSString *)eventName log:(NSDictionary<NSString *, NSString*> * _Nullable)log {
    
    CEEventLog * eventLog = [[CEEventLog alloc] initWithEventName:eventName log:log];
    
    [self p_logEvent:eventLog completion:^(BOOL success) {
        
        if (!success) {
            self.failedLogs[eventName] = eventLog;
        }
        
    }];
    
}

- (void)logPage:(NSString *)pageName {
    
    [self logPage:pageName log:nil];
    
}

- (void)logPage:(NSString *)pageName log:(NSDictionary<NSString *,NSString *> * _Nullable)log {
    
    CEPageLog * pageLog = [[CEPageLog alloc] initWithPageName:pageName log:log];
    
    [self p_logEvent:pageLog completion:^(BOOL success) {
        
        if (!success) {
            self.failedLogs[pageName] = pageLog;
        }
        
    }];
    
}

- (void)startDurationPageLog:(NSString *)pageName {
    
    if (!self.durationLogs[pageName]) {
        
        CEDurationPageLog * log = [[CEDurationPageLog alloc] initWithPageName:pageName];
        
        [log start];
        
        self.durationLogs[pageName] = log;
        
    }
    
}

- (void)pauseDurationPageLog:(NSString *)pageName {
    
    id<CEDurationLogItem> pageLog = self.durationLogs[pageName];
    
    if (pageLog && [pageLog conformsToProtocol:@protocol(CEDurationLogItem)]) {
        [pageLog pause];
    }
    
}

- (void)stopDurationPageLog:(NSString *)pageName {
    
    id<CEDurationLogItem> pageLog = self.durationLogs[pageName];
    
    if (pageLog && [pageLog conformsToProtocol:@protocol(CEDurationLogItem)]) {
        
        [pageLog stop];
        
        [self p_logEvent:pageLog completion:^(BOOL success) {
            
            [self.durationLogs removeObjectForKey:pageName];
            
            if (!success) {
                self.failedLogs[pageName] = pageLog;
            }
            
        }];
        
    }
    
}

- (void)startDurationLogEvent:(NSString *)eventName log:(NSDictionary<NSString *,NSString *> *)log {
    
    if (!self.durationLogs[eventName]) {
        
        CEDurationEventLog * eventLog = [[CEDurationEventLog alloc] initWithEventName:eventName log:log];
        
        [eventLog start];
        
        self.durationLogs[eventName] = eventLog;
        
    }
    
}

- (void)stopDurationLogEvent:(NSString *)eventName log:(NSDictionary<NSString *,NSString *> *)log {
    
    id<CEDurationLogItem> eventLog = self.durationLogs[eventName];
    
    if (eventLog && [eventLog conformsToProtocol:@protocol(CEDurationLogItem)]) {
        
        [eventLog stop];
        
        [self p_logEvent:eventLog completion:^(BOOL success) {
        
            [self.durationLogs removeObjectForKey:eventLog];
            
            if (!success) {
                self.failedLogs[eventName] = eventLog;
            }
            
        }];
        
    }
    
}

- (void)updateDurationLogEvent:(NSString *)eventName log:(NSDictionary<NSString *,NSString *> *)log {
    
    id<CELogUpdate> eventLog = self.durationLogs[eventName];
    
    if (eventLog && [eventLog conformsToProtocol:@protocol(CELogUpdate)]) {
        
        [eventLog update:log];
        
    }
    
}

- (void)removeDurationLogEvent:(NSString *)eventName {
    
    [self.durationLogs removeObjectForKey:eventName];
    
}

- (void)removeDurationPageLog:(NSString *)pageName {
    
    [self.durationLogs removeObjectForKey:pageName];
    
}

#pragma mark - 私有方法


- (void)p_logEvent:(id<CELogItem>)logItem completion:(void(^)(BOOL success))completion {
    
    dispatch_async(self->_workQueue, ^{
        
        NSMutableDictionary * finalLog = [NSMutableDictionary dictionary];
        
        NSMutableDictionary * commonLogDic = [self.currentCommonLog.content mutableCopy];
        
        [commonLogDic enumerateKeysAndObjectsUsingBlock:^(NSString *  _Nonnull key, NSString *  _Nonnull obj, BOOL * _Nonnull stop) {
            finalLog[key] = obj;
        }];
        
        NSDictionary * logContentDic = [logItem content];
        
        [logContentDic enumerateKeysAndObjectsUsingBlock:^(NSString *  _Nonnull key, NSString *  _Nonnull obj, BOOL * _Nonnull stop) {
            finalLog[key] = obj;
        }];
        
        if (self.getDeviceUUID) {
            finalLog[@"deviceId"] = self.getDeviceUUID();
        }
        
        if (self.getFirstOpenTimeInterval) {
            finalLog[@"firstOpen"] = [NSString stringWithFormat:@"%@", @(self.getFirstOpenTimeInterval())];
        }
        
        if (self.getChannel) {
            finalLog[@"channel"] = self.getChannel();
        }
        
        RawLogGroup * logGroup = [[RawLogGroup alloc] initWithTopic:@"" andSource:@""];
        
        RawLog * aliyunLog = [[RawLog alloc] init];
        
        [finalLog enumerateKeysAndObjectsUsingBlock:^(NSString *  _Nonnull key, NSString *  _Nonnull obj, BOOL * _Nonnull stop) {
            [aliyunLog PutContent:obj withKey:key];
        }];
        
        [logGroup PutLog:aliyunLog];
        
        [self.aliyunLogClient PostLog:logGroup logStoreName:self->_logConfig.storeName call:^(NSURLResponse * _Nullable response, NSError * _Nullable error) {
            
            dispatch_async(dispatch_get_main_queue(), ^{
                if (!error) {
                    completion(YES);
                }else {
                    completion(NO);
                }
            });
            
        }];
        
    });
    
}



@end
